#include<stdio.h>  
#include<stdlib.h>  
#include<unistd.h>  
#include<pthread.h>  
#include<semaphore.h>  
#define PRODUCER_NUM 10 //小和尚数目  
#define CONSUMER_NUM 10 //老和尚数目  
#define POOL_SIZE    31  //缓冲池大小 一个缸30桶水 
int pool[POOL_SIZE];    //缓冲区数组 大小为POOL_SIZE（30） 
int head=0; //缓冲池读取指针  
int rear=0; //缓冲池写入指针  
sem_t  full;       //同步信号信号量，表示缓冲区有可用间  
sem_t  empty;      //同步信号量，表示缓冲区有可用品  
sem_t  pail;//桶的个数
pthread_mutex_t mutex; //互斥信号量 缸
pthread_mutex_t well; //互斥信号量 井
void * producer_fun(void *arg)  
{   //小和尚 打水
    while (1)  
    {  
        sleep(rand()%10+1); //随机休息
        sem_wait(&full); //判断水缸是否还有容量，有则减一，程序向下执行 
        sem_wait(&pail); //申请一个桶
        printf("小和尚 %ld 号 拿了一个桶\n", (long)arg); 
        pthread_mutex_lock(&well); //占用水井
        printf("小和尚 %ld 号 正在从井里取水\n", (long)arg); 
        pthread_mutex_unlock(&well); //取水后离开井
        pthread_mutex_lock(&mutex);  //占用水缸
        //生产者往缓冲池中写入数据  
        pool[rear] = 1;  
        rear = (rear + 1) % POOL_SIZE;  
        printf("小和尚 %ld 号 正在倒水\n", (long)arg);  
        printf("桶里现在有 %d 桶水\n",(rear-head+POOL_SIZE)%POOL_SIZE);
        pthread_mutex_unlock(&mutex);  //离开水缸
        sem_post(&pail); //还桶
        printf("小和尚 %ld 号 还桶\n", (long)arg); 
        sem_post(&empty);  //full+1，即水缸中的水的桶数加1
    }  
}   
void * consumer_fun(void *arg)  
{  //老和尚 喝水
    while (1)  
    {  
        int data;  
        sleep(rand()%10+1);  //随机休息
        sem_wait(&empty); //看是否有水，有则减一，程序向下执行  
        sem_wait(&pail); //申请一个桶
        printf("老和尚 %ld 号 拿了一个桶\n", (long)arg);
        pthread_mutex_lock(&mutex);  //占用水缸 
        //消费者从缓冲池读取数据  
        data = pool[head];  
        head = (head + 1) % POOL_SIZE;  
        printf("老和尚 %ld 号正在取水\n", (long)arg);  
        printf("桶里现在有 %d 桶水\n",(rear-head+POOL_SIZE)%POOL_SIZE);  
        pthread_mutex_unlock(&mutex);  //用完水缸，释放资源
        sem_post(&pail); //还桶
        printf("老和尚 %ld 号 还桶\n", (long)arg); 
        sem_post(&full);  
    }  
}  


int main()  
{  


    pthread_t producer_id[PRODUCER_NUM];  
    pthread_t consumer_id[CONSUMER_NUM];  
    pthread_mutex_init(&mutex, NULL);   //初始化互斥量 缸 
    pthread_mutex_init(&well, NULL);   //初始化互斥量  井


    int ret = sem_init(&full, 0, POOL_SIZE-1); 
    if (ret != 0)  
    {  
        printf("sem_init error");  
        exit(0);  
    }  //初始化信号量 full为缓冲池大小  
    
    ret = sem_init(&empty, 0, 0);
    if (ret != 0)  
    {  
        printf("sem_init error");  
        exit(0);  
    }  //初始化信号量 empty为0，开始时缓冲池中没有数据  

    ret = sem_init(&pail, 0, 10);
    if (ret != 0)  
    {  
        printf("sem_init error");  
        exit(0);  
    }  //初始化信号量 pail为10，一共有10个桶 
   
    long i; 
    for ( i = 0; i < PRODUCER_NUM; i++)  
    {  
        //创建生产者线程  
    ret =pthread_create(&producer_id[i], NULL, producer_fun, (void*)i);  
        if (ret != 0)  
        {  
            printf("producer_id error");  
            exit(0);  
        }  
        //创建消费者线程  
    ret = pthread_create(&consumer_id[i], NULL, consumer_fun, (void*)i);
        if (ret != 0)  
        {  
            printf("consumer_id error");  
            exit(0);  
        }  
    }  
    for(i=0;i<PRODUCER_NUM;i++)  
    {  
        pthread_join(producer_id[i],NULL);  
        pthread_join(consumer_id[i],NULL);  
    }   
    exit(0);  
}
